package com.yangtu.nearbyshop.admin.service;

import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.PageInfo;
import com.sun.org.apache.xpath.internal.operations.Or;
import com.yangtu.nearbyshop.admin.util.AdminResponseCode;
import com.yangtu.nearbyshop.core.corg.CorgChannel;
import com.yangtu.nearbyshop.core.notify.NotifyService;
import com.yangtu.nearbyshop.core.notify.NotifyType;
import com.yangtu.nearbyshop.core.system.SystemConfig;
import com.yangtu.nearbyshop.core.util.JacksonUtil;
import com.yangtu.nearbyshop.core.util.ResponseUtil;
import com.yangtu.nearbyshop.db.domain.*;
import com.yangtu.nearbyshop.db.service.*;
import com.yangtu.nearbyshop.db.service.itf.INearbyshopOrderRefundService;
import com.yangtu.nearbyshop.db.service.itf.INearbyshopOrderService;
import com.yangtu.nearbyshop.db.util.OrderHandleOption;
import com.yangtu.nearbyshop.db.util.OrderUtil;
import com.yangtu.nearbyshop.db.vo.OrderSettleVo;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.yangtu.nearbyshop.core.corg.Const.*;

@Service

public class AdminOrderService {
    private final Log logger = LogFactory.getLog(AdminOrderService.class);

    @Autowired
    private NearbyshopOrderGoodsService orderGoodsService;
    @Autowired
    private NearbyshopOrderService orderService;
    @Autowired
    private INearbyshopOrderService orderService2;
    @Autowired
    private INearbyshopOrderRefundService refundService;
    @Autowired
    private NearbyshopGoodsProductService productService;
    @Autowired
    private NearbyshopUserService userService;
    @Autowired
    private NearbyshopCommentService commentService;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private NotifyService notifyService;
    @Autowired
    private NearbyshopMercService mercService;
    @Autowired
    private CorgChannel cnlPayService;

    @Autowired
    private NearbyshopAdminService adminService;

    public Object list(String adminName,Integer userId, String orderSn, List<Short> orderStatusArray,
                       Integer page, Integer limit, String sort, String order,String startTime,String endTime) {

        Subject currentUser = SecurityUtils.getSubject();
        NearbyshopAdmin admin = (NearbyshopAdmin) currentUser.getPrincipal();
        Integer adminId = admin.getId();
        for( Integer roleId : admin.getRoleIds()){
            if(roleId.equals(new Integer(1))){
                adminId = null;
            }
        }

        if(!StringUtils.isEmpty(adminName)){
            List<NearbyshopAdmin> adminSearch = adminService.findAdmin(adminName);
            if(adminSearch.size()>0){
                admin = adminSearch.get(0);
                adminId = adminSearch.get(0).getId();
            }else{
                adminId = -1;
            }
        }

        List<NearbyshopOrder> orderList = orderService.querySelective(adminId,userId, orderSn,
                orderStatusArray, page, limit, sort, order,startTime,endTime);
        if(adminId != null){
            for(NearbyshopOrder od : orderList){
                od.setAdminName(admin.getUsername());
            }
        }else {
            List<NearbyshopAdmin> adminList = adminService.querySelective(null,1,
                    10000,"add_time","asc");
            Map<Integer, NearbyshopAdmin> maps = adminList.stream().collect(Collectors.toMap(NearbyshopAdmin::getId,
                    Function.identity(), (key1, key2) -> key2));
            for(NearbyshopOrder od : orderList){
                od.setAdminName(maps.get(od.getAdminId()).getUsername());
            }
        }

        long total = PageInfo.of(orderList).getTotal();

        int allGodosNum = 0;
        BigDecimal allOrderPrice = new BigDecimal(0);
        BigDecimal allActualPrice = new BigDecimal(0);
        for(NearbyshopOrder od : orderList){
            int gnum = 0;
            String goodsDesc = "";
            int i = 1;
            List<NearbyshopOrderGoods> goodsList = orderGoodsService.queryByOid(od.getId());
            for(NearbyshopOrderGoods og : goodsList){
                gnum += og.getNumber();
                goodsDesc += i + "."+og.getGoodsName() + " " + ArrayUtils.toString(og.getSpecifications(),",")+
                        " (" + og.getNumber() + ") (" + og.getGoodsId() + "),";
                i++;
            }

            NearbyshopMerc merc = mercService.queryByMercNo(od.getMercNo());
            od.setGoodsDesc(goodsDesc.substring(0,goodsDesc.length()-1));
            od.setGoodsNum(gnum);
            od.setMercName(null==merc?"":merc.getMercName());
            allGodosNum += gnum;
            allOrderPrice = allOrderPrice.add(od.getOrderPrice());
            allActualPrice = allActualPrice.add(od.getActualPrice());
        }

        OrderSettleVo settleVo = new OrderSettleVo();
        settleVo.setTotalGoosNum(allGodosNum);
        settleVo.setTotalOrderPrice(allOrderPrice.toString());
        settleVo.setTotalActualPrice(allActualPrice.toString());

        Map<String, Object> data = new HashMap<>();
        data.put("total", total);
        data.put("items", orderList);
        data.put("settle", settleVo);

        return ResponseUtil.ok(data);
    }

    public Object detail(Integer id) {
        NearbyshopOrder order = orderService.findById(id);
        List<NearbyshopOrderGoods> orderGoods = orderGoodsService.queryByOid(id);
        UserVo user = userService.findUserVoById(order.getUserId());
        user.setNickname(new String(Base64.getDecoder().decode(user.getNickname())));
        Map<String, Object> data = new HashMap<>();
        data.put("order", order);
        data.put("orderGoods", orderGoods);
        data.put("user", user);

        return ResponseUtil.ok(data);
    }

    /**
     * 订单退款
     * <p>
     * 1. 检测当前订单是否能够退款;
     * 2. 微信退款操作;
     * 3. 设置订单退款确认状态；
     * 4. 订单商品库存回库。
     * <p>
     * TODO
     * 虽然接入了微信退款API，但是从安全角度考虑，建议开发者删除这里微信退款代码，采用以下两步走步骤：
     * 1. 管理员登录微信官方支付平台点击退款操作进行退款
     * 2. 管理员登录nearbyshop管理后台点击退款操作进行订单状态修改和商品库存回库
     *
     * @param body 订单信息，{ orderId：xxx }
     * @return 订单退款操作结果
     */
    @Transactional
    public Object refund(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        String refundMoney = JacksonUtil.parseString(body, "refundMoney");
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }
        if (StringUtils.isEmpty(refundMoney)) {
            return ResponseUtil.badArgument();
        }

        NearbyshopOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        if (order.getActualPrice().compareTo(new BigDecimal(refundMoney)) != 0) {
            return ResponseUtil.fail("退款金额有误");
        }

        // 如果订单不是退款状态，则不能退款
        if (!order.getOrderStatus().equals(OrderUtil.STATUS_REFUND)) {
            return ResponseUtil.fail(AdminResponseCode.ORDER_CONFIRM_NOT_ALLOWED, "订单不能退款");
        }

        // 微信退款
//        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
//        wxPayRefundRequest.setOutTradeNo(order.getOrderSn());
//        wxPayRefundRequest.setOutRefundNo("refund_" + order.getOrderSn());
//        // 元转成分
//        Integer totalFee = order.getActualPrice().multiply(new BigDecimal(100)).intValue();
//        wxPayRefundRequest.setTotalFee(totalFee);
//        wxPayRefundRequest.setRefundFee(totalFee);
//
//        WxPayRefundResult wxPayRefundResult = null;
//        try {
//            wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
//        } catch (WxPayException e) {
//            e.printStackTrace();
//            return ResponseUtil.fail(AdminResponseCode.ORDER_REFUND_FAILED, "订单退款失败");
//        }
//        if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
//            logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
//            return ResponseUtil.fail(AdminResponseCode.ORDER_REFUND_FAILED, "订单退款失败");
//        }

        Map<String, String> context = new HashMap<>();
        context.put("tranId", order.getPayOrderSn());
        context.put("amount", order.getActualPrice().toPlainString());

        try {
            Map<String, String> result = cnlPayService.refundApply(context);
            if (!result.get(CMM_PARAM_RETURN_CODE).equals(SUC_RETURN_CODE)) {
                logger.warn("refund fail: " + result.get(CMM_PARAM_RETURN_MSG));
                return ResponseUtil.fail(AdminResponseCode.ORDER_REFUND_FAILED, "订单退款失败");
            }
            order.setShipSn(result.get(UP_CORG_TRAN_ID));
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 设置订单取消状态
        order.setOrderStatus(OrderUtil.STATUS_REFUND_CONFIRM);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 商品货品数量增加
        List<NearbyshopOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
        for (NearbyshopOrderGoods orderGoods : orderGoodsList) {
            Integer productId = orderGoods.getProductId();
            Short number = orderGoods.getNumber();
            if (productService.addStock(productId, number) == 0) {
                throw new RuntimeException("商品货品库存增加失败");
            }
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 退款成功通知用户, 例如“您申请的订单退款 [ 单号:{1} ] 已成功，请耐心等待到账。”
        // 注意订单号只发后6位
        notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND, new String[]{order.getOrderSn().substring(8, 14)});

        return ResponseUtil.ok();
    }

    /**
     * 订单退款
     * <p>
     * 1. 检测当前订单是否能够退款;
     * 2. 微信退款操作;
     * 3. 设置订单退款确认状态；
     * 4. 订单商品库存回库。
     * <p>
     * TODO
     * 虽然接入了微信退款API，但是从安全角度考虑，建议开发者删除这里微信退款代码，采用以下两步走步骤：
     * 1. 管理员登录微信官方支付平台点击退款操作进行退款
     * 2. 管理员登录nearbyshop管理后台点击退款操作进行订单状态修改和商品库存回库
     *
     * @param body 订单信息，{ orderId：xxx }
     * @return 订单退款操作结果
     */
    @Transactional
    public Object refundNative(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        String refundMoney = JacksonUtil.parseString(body, "refundMoney");
        if (orderId == null) {
            return ResponseUtil.badArgument("缺少订单ID，无法退款");
        }
        if (StringUtils.isEmpty(refundMoney)) {
            return ResponseUtil.badArgument("缺少退款金额无法退款");
        }

        NearbyshopOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument("订单不存在，无法退款");
        }

        if (order.getActualPrice().compareTo(new BigDecimal(refundMoney)) != 0) {
            return ResponseUtil.fail("订单金额不符，退款失败");
        }

        // 如果订单不是退款状态，则不能退款
        if (order.getOrderStatus().equals(OrderUtil.STATUS_PAY) ||
                order.getOrderStatus().equals(OrderUtil.STATUS_SHIP) ||
                order.getOrderStatus().equals(OrderUtil.STATUS_REFUND) ||
                order.getOrderStatus().equals(OrderUtil.STATUS_CONFIRM) ||
                order.getOrderStatus().equals(OrderUtil.STATUS_AUTO_CONFIRM)
        ) {
            logger.info("refund info: 可以退款");
        }else if(order.getOrderStatus().equals(OrderUtil.STATUS_REFUND_CONFIRM)){
            return ResponseUtil.fail(AdminResponseCode.ORDER_CONFIRM_NOT_ALLOWED, "订单已经退款");
        }

        logger.info("refund info: 开始退款");
        // 微信退款
        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
        wxPayRefundRequest.setOutTradeNo(order.getOrderSn());
        wxPayRefundRequest.setOutRefundNo("refund_" + order.getOrderSn());
        // 元转成分
        Integer totalFee = order.getActualPrice().multiply(new BigDecimal(100)).intValue();
        wxPayRefundRequest.setTotalFee(totalFee);
        wxPayRefundRequest.setRefundFee(totalFee);

        WxPayRefundResult wxPayRefundResult = null;
        try {
            wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
            logger.info("refund info: "+ wxPayRefundResult.getResultCode()+ "-" + wxPayRefundResult.getReturnMsg());
        } catch (WxPayException e) {
            e.printStackTrace();
            return ResponseUtil.fail(AdminResponseCode.ORDER_REFUND_FAILED, "订单退款失败");
        }
        if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
            logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
            return ResponseUtil.fail(AdminResponseCode.ORDER_REFUND_FAILED, "订单退款失败");
        }

//        Map<String, String> context = new HashMap<>();
//        context.put("tranId", order.getOrderSn());
//        context.put("amount", order.getActualPrice().toPlainString());
//
//        try {
//            Map<String, String> result = cnlPayService.refundApply(context);
//            if (!result.get(CMM_PARAM_RETURN_CODE).equals(SUC_RETURN_CODE)) {
//                logger.warn("refund fail: " + result.get(CMM_PARAM_RETURN_MSG));
//                return ResponseUtil.fail(AdminResponseCode.ORDER_REFUND_FAILED, "订单退款失败");
//            }
//            order.setShipSn(result.get(UP_CORG_TRAN_ID));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

        // 设置订单取消状态
        order.setOrderStatus(OrderUtil.STATUS_REFUND_CONFIRM);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 商品货品数量增加
        List<NearbyshopOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
        for (NearbyshopOrderGoods orderGoods : orderGoodsList) {
            Integer productId = orderGoods.getProductId();
            Short number = orderGoods.getNumber();
            if (productService.addStock(productId, number) == 0) {
                throw new RuntimeException("商品货品库存增加失败");
            }
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 退款成功通知用户, 例如“您申请的订单退款 [ 单号:{1} ] 已成功，请耐心等待到账。”
        // 注意订单号只发后6位
        notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND, new String[]{order.getOrderSn().substring(8, 14)});

        return ResponseUtil.ok();
    }

    /**
     * 订单退款
     * <p>
     * 1. 检测当前订单是否能够退款;
     * 2. 微信退款操作;
     * 3. 设置订单退款确认状态；
     * 4. 订单商品库存回库。
     * <p>
     * TODO
     * 虽然接入了微信退款API，但是从安全角度考虑，建议开发者删除这里微信退款代码，采用以下两步走步骤：
     * 1. 管理员登录微信官方支付平台点击退款操作进行退款
     * 2. 管理员登录nearbyshop管理后台点击退款操作进行订单状态修改和商品库存回库
     *
     * @param body 订单信息，{ orderId：xxx }
     * @return 订单退款操作结果
     */
    @Transactional
    public Object unrefund(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }

        NearbyshopOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        // 如果订单不是退款状态，则不能退款
        if (!order.getOrderStatus().equals(OrderUtil.STATUS_REFUND)) {
            return ResponseUtil.fail(AdminResponseCode.ORDER_CONFIRM_NOT_ALLOWED, "订单不能取消退款");
        }

        // 设置订单取消状态
        order.setOrderStatus(OrderUtil.STATUS_PAY);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        return ResponseUtil.ok();
    }

    /**
     * 发货
     * 1. 检测当前订单是否能够发货
     * 2. 设置订单发货状态
     *
     * @param body 订单信息，{ orderId：xxx, shipSn: xxx, shipChannel: xxx }
     * @return 订单操作结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    public Object ship(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        String shipSn = JacksonUtil.parseString(body, "shipSn");
        String shipChannel = JacksonUtil.parseString(body, "shipChannel");
        if (orderId == null || shipSn == null || shipChannel == null) {
            return ResponseUtil.badArgument("物流信息不全，发货失败");
        }

        NearbyshopOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument("订单不存在");
        }

        // 如果订单不是已付款状态，则不能发货
        if (!order.getOrderStatus().equals(OrderUtil.STATUS_PAY)
                && !order.getOrderStatus().equals(OrderUtil.STATUS_SHIP)) {
            return ResponseUtil.fail(AdminResponseCode.ORDER_CONFIRM_NOT_ALLOWED, "当前订单不能发货，请确认订单状态");
        }

        order.setOrderStatus(OrderUtil.STATUS_SHIP);
        order.setShipSn(shipSn);
        order.setShipChannel(shipChannel);
        order.setShipTime(LocalDateTime.now());
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return ResponseUtil.updatedDateExpired();
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 发货会发送通知短信给用户:          *
        // "您的订单已经发货，快递公司 {1}，快递单 {2} ，请注意查收"
        //notifyService.notifySmsTemplate(order.getMobile(), NotifyType.SHIP, new String[]{shipChannel, shipSn});

        NearbyshopUser user = userService.findById(order.getUserId());
        NearbyshopAdmin admin = adminService.findById(order.getAdminId());
        // 请依据自己的模版消息配置更改参数
        String[] parms = new String[]{
                "21克铺子",
                new String(Base64.getDecoder().decode(user.getNickname())),
                order.getOrderSn(),
                order.getAddress()
        };

        notifyService.notifyWxTemplate(user.getWeixinOpenid(),
                NotifyType.SHIP, parms, "pages/index/index?orderId=" + order.getId());
        return ResponseUtil.ok();
    }


    /**
     * 回复订单商品
     *
     * @param body 订单信息，{ orderId：xxx }
     * @return 订单操作结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    public Object reply(String body) {
        Integer commentId = JacksonUtil.parseInteger(body, "commentId");
        if (commentId == null || commentId == 0) {
            return ResponseUtil.badArgument();
        }
        // 目前只支持回复一次
        if (commentService.findById(commentId) != null) {
            return ResponseUtil.fail(AdminResponseCode.ORDER_REPLY_EXIST, "订单商品已回复！");
        }
        String content = JacksonUtil.parseString(body, "content");
        if (StringUtils.isEmpty(content)) {
            return ResponseUtil.badArgument();
        }
        // 创建评价回复
        NearbyshopComment comment = new NearbyshopComment();
        comment.setType((byte) 2);
        comment.setValueId(commentId);
        comment.setContent(content);
        comment.setUserId(0);                 // 评价回复没有用
        comment.setStar((short) 0);           // 评价回复没有用
        comment.setHasPicture(false);        // 评价回复没有用
        comment.setPicUrls(new String[]{});  // 评价回复没有用
        commentService.save(comment);

        return ResponseUtil.ok();
    }

    public Object getProfitList(String mercNo,String startDt, String endDt,
                       Integer page, Integer limit) {

        List<NearbyshopMerc> mercList = mercService.queryByMercNoList(mercNo, page, limit);
        long total = PageInfo.of(mercList).getTotal();
        List<Map<String,String>> profits = new ArrayList<>();
        Map<String,String> profitVo;
        String curMercNo;
        String selfProfit;
        for (NearbyshopMerc neraMerc: mercList) {
            profitVo = new HashMap<>();
            curMercNo = neraMerc.getMercNo();
            profitVo.put("mercNo", curMercNo);
            profitVo.put("mercName", neraMerc.getMercName());
            selfProfit = orderService.getProfitByDt(curMercNo, startDt, endDt);
            List<Map<String,String>> referprofitList = orderService.getReferProfitByMerc(curMercNo, startDt, endDt);
            String referProfit;
            String sumProfit;
            if (referprofitList.size() == 0) {
                referProfit = "0.00";
                sumProfit = selfProfit;
            }else {
                referProfit = new BigDecimal(referprofitList.get(0).get("mercProfit")).multiply(SystemConfig.getMercReferPercent()).setScale(2, BigDecimal.ROUND_UP).toPlainString();
                sumProfit = new BigDecimal(referProfit).add(new BigDecimal(selfProfit)).setScale(2, BigDecimal.ROUND_UP).toPlainString();
            }
            profitVo.put("mercProfit", sumProfit);
            profitVo.put("referProfit", referProfit);
            profitVo.put("selfProfit", selfProfit);
            profitVo.put("cardNo", neraMerc.getCardNo());
            profitVo.put("realName", neraMerc.getRealName());
            profitVo.put("mobile", neraMerc.getMobile());
            profitVo.put("bankName", neraMerc.getBankNm());
            profits.add(profitVo);
        }



//        List<Map<String,String>> profitList = orderService.getProfitByMerc(mercNo, startDt, endDt, page, limit);
//
//        long total = PageInfo.of(profitList).getTotal();
//        List<Map<String,String>> profits = new ArrayList<>();
//        for (Map<String,String> profitMap: profitList) {
//            Map<String,String> profitVo = new HashMap<>();
//            List<Map<String,String>> referprofitList = orderService.getReferProfitByMerc(profitMap.get("merc_no"), startDt, endDt);
//            profitVo.put("mercNo", profitMap.get("merc_no"));
//            profitVo.put("mercName", profitMap.get("merc_name"));
//            String selfProfit = profitMap.get("mercProfit");
//            String referProfit;
//            String sumProfit;
//            if (referprofitList.size() == 0) {
//                referProfit = "0";
//                sumProfit = selfProfit;
//            }else {
//                referProfit = new BigDecimal(referprofitList.get(0).get("mercProfit")).multiply(SystemConfig.getMercReferPercent()).toPlainString();
//                sumProfit = new BigDecimal(referProfit).add(new BigDecimal(selfProfit)).setScale(2, BigDecimal.ROUND_UP).toPlainString();
//            }
//            profitVo.put("mercProfit", sumProfit);
//            profitVo.put("referProfit", referProfit);
//            profitVo.put("selfProfit", selfProfit);
//            profitVo.put("cardNo", profitMap.get("card_no"));
//            profitVo.put("realName", profitMap.get("real_name"));
//            profitVo.put("mobile", profitMap.get("mobile"));
//            profitVo.put("bankName", profitMap.get("bank_nm"));
//            profits.add(profitVo);
//        }

        Map<String, Object> data = new HashMap<>();
        data.put("total", total);
        data.put("items", profits);

        return ResponseUtil.ok(data);
}

    public Object goodsOrderbyGoodsList(String mercNo, String goodId, String ordState,
                                             String startTm, String endTm,
                                             Integer page, Integer limit) {

        List<Map<String,String>> goodsOrderList = orderGoodsService.getGoodsByCond(mercNo, goodId, ordState,
                startTm, endTm, page, limit, 0);

        long total = PageInfo.of(goodsOrderList).getTotal();
        List<Map<String,String>> goodsList = new ArrayList<>();
        for (Map<String,String> goodsMap: goodsOrderList) {
            Map<String,String> goodsVo = new HashMap<>();
            goodsVo.put("goodsId", String.valueOf(goodsMap.get("goods_id")));
            goodsVo.put("goodsNm", goodsMap.get("goods_name"));
            goodsVo.put("specifications", goodsMap.get("specifications"));
            goodsVo.put("goodsNum", String.valueOf(goodsMap.get("goodsNum")));
            goodsList.add(goodsVo);
        }

        Map<String, Object> data = new HashMap<>();
        data.put("total", total);
        data.put("items", goodsList);

        return ResponseUtil.ok(data);
    }

    public Object goodsOrderbyMercList(String mercNo, String goodId, String ordState,
                                        String startTm, String endTm,
                                        Integer page, Integer limit) {

        List<Map<String,String>> goodsOrderList = orderGoodsService.getGoodsByCond(mercNo, goodId, ordState, startTm, endTm, page, limit, 1);

        long total = PageInfo.of(goodsOrderList).getTotal();
        List<Map<String,String>> goodsList = new ArrayList<>();
        for (Map<String,String> goodsMap: goodsOrderList) {
            Map<String,String> goodsVo = new HashMap<>();
            NearbyshopMerc nearbyshopMerc =  mercService.queryByMercNo(goodsMap.get("merc_no"));
            if (nearbyshopMerc != null) {
                goodsVo.put("mercNo", goodsMap.get("merc_no"));
                goodsVo.put("mercNm", nearbyshopMerc.getMercName());
                goodsVo.put("mercAddr", nearbyshopMerc.getMercAddr());
                goodsVo.put("goodsId", goodsMap.get("goods_id"));
                goodsVo.put("goodsNm", goodsMap.get("goods_name"));
                goodsVo.put("specifications", goodsMap.get("specifications"));
                goodsVo.put("goodsNum", goodsMap.get("goodsNum"));
                goodsList.add(goodsVo);
            }else {
                goodsVo.put("mercNo", goodsMap.get("merc_no"));
                goodsVo.put("mercNm", "商户已删除");
                goodsVo.put("mercAddr", "商户已删除");
                goodsVo.put("goodsId", goodsMap.get("goods_id"));
                goodsVo.put("goodsNm", goodsMap.get("goods_name"));
                goodsVo.put("specifications", goodsMap.get("specifications"));
                goodsVo.put("goodsNum", goodsMap.get("goodsNum"));
                goodsList.add(goodsVo);
            }
        }

        Map<String, Object> data = new HashMap<>();
        data.put("total", total);
        data.put("items", goodsList);

        return ResponseUtil.ok(data);
    }

    public Object goodsOrderbyUsersList(String mercNo, String goodId, String ordState,
                                        String startTm, String endTm,
                                        Integer page, Integer limit) {

        List<Map<String,String>> goodsOrderList = orderGoodsService.getGoodsByCond(mercNo, goodId, ordState, startTm, endTm, page, limit, 2);

        long total = PageInfo.of(goodsOrderList).getTotal();
        List<Map<String,String>> goodsList = new ArrayList<>();
        for (Map<String,String> goodsMap: goodsOrderList) {
            Map<String,String> goodsVo = new HashMap<>();
            NearbyshopMerc nearbyshopMerc =  mercService.queryByMercNo(goodsMap.get("merc_no"));
            if (nearbyshopMerc != null) {

                goodsVo.put("mercNo", goodsMap.get("merc_no"));
                goodsVo.put("mercNm", nearbyshopMerc.getMercName());
                goodsVo.put("mercAddr", nearbyshopMerc.getMercAddr());
                goodsVo.put("consignee", goodsMap.get("consignee"));
                goodsVo.put("mobile", goodsMap.get("mobile"));
                goodsVo.put("goodsId", goodsMap.get("goods_id"));
                goodsVo.put("goodsNm", goodsMap.get("goods_name"));
                goodsVo.put("specifications", goodsMap.get("specifications"));
                goodsVo.put("goodsNum", goodsMap.get("goodsNum"));
                goodsList.add(goodsVo);
            }else {
                goodsVo.put("mercNo", goodsMap.get("merc_no"));
                goodsVo.put("mercNm", "商户已删除");
                goodsVo.put("mercAddr", "商户已删除");
                goodsVo.put("consignee", goodsMap.get("consignee"));
                goodsVo.put("mobile", goodsMap.get("mobile"));
                goodsVo.put("goodsId", goodsMap.get("goods_id"));
                goodsVo.put("goodsNm", goodsMap.get("goods_name"));
                goodsVo.put("specifications", goodsMap.get("specifications"));
                goodsVo.put("goodsNum", goodsMap.get("goodsNum"));
                goodsList.add(goodsVo);
            }
        }

        Map<String, Object> data = new HashMap<>();
        data.put("total", total);
        data.put("items", goodsList);

        return ResponseUtil.ok(data);
    }

    /**
     * 订单申请退款
     * <p>
     * 1. 检测当前订单是否能够退款；
     * 2. 设置订单申请退款状态。
     *
     * @return 订单退款操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Object refundGroup(Integer orderId) {
        NearbyshopOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isRefund()) {
            return ResponseUtil.fail("订单不能退款");
        }

        NearbyshopOrder2 order2 = orderService2.getById(orderId);
        NearbyshopOrderRefund refund = new NearbyshopOrderRefund();
        BeanUtils.copyProperties(order2,refund);
        refund.setOrderId(order2.getId());
        refund.setId(null);
        refund.setApplyTime(new Date());
        refund.setHandleTime(new Date());
        refund.setRefundStatus(1);
        refund.setRefundPrice(order2.getActualPrice());
        refund.setRefundReason("团购失败退款");
        refund.setRefundBy("3");
        //多加入一个状态：已采购
        if(order.getOrderStatus().equals(OrderUtil.STATUS_PAY) && order.getPurchaseStatus().equals(1)){
            refund.setOrderStatus(OrderUtil.STATUS_PURCHASE.intValue());
        }
        //设置商品数量
        int gnum = 0;
        int i = 1;
        List<NearbyshopOrderGoods> goodsList = orderGoodsService.queryByOid(order.getId());
        for(NearbyshopOrderGoods og : goodsList){
            gnum += og.getNumber();
        }
        refund.setGoodsNum(gnum);
        refundService.save(refund);

        // 设置订单申请退款状态
        order.setOrderStatus(OrderUtil.STATUS_REFUND);
//        if (orderService.updateWithOptimisticLocker(order) == 0) {
//            return ResponseUtil.updatedDateExpired();
//        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 有用户申请退款，邮件通知运营人员
        //notifyService.notifyMail("订单退款", order.toString());


        //新增方法，申请退款后直接退
        Map<String, String> context = new HashMap<>();
        context.put("tranId", order.getOrderSn());
        context.put("amount", order.getActualPrice().toPlainString());

        try {
            Map<String, String> result = cnlPayService.refundApply(context);
            if (!result.get(CMM_PARAM_RETURN_CODE).equals(SUC_RETURN_CODE)) {
                logger.warn("refund fail: " + result.get(CMM_PARAM_RETURN_MSG));
                return ResponseUtil.fail("订单退款失败");
            }
            order.setShipSn(result.get(UP_CORG_TRAN_ID));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        // 微信原生退款
        /*WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
        wxPayRefundRequest.setOutTradeNo(order.getOrderSn());
        wxPayRefundRequest.setOutRefundNo("refund_" + order.getOrderSn());
        // 元转成分
        Integer totalFee = order.getActualPrice().multiply(new BigDecimal(100)).intValue();
        wxPayRefundRequest.setTotalFee(totalFee);
        wxPayRefundRequest.setRefundFee(totalFee);

        WxPayRefundResult wxPayRefundResult = null;
        try {
            wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
        } catch (WxPayException e) {
            e.printStackTrace();
            return ResponseUtil.fail( "订单退款失败");
        }
        if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
            logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
            return ResponseUtil.fail( "订单退款失败");
        }*/


        // 设置订单取消状态
        order.setOrderStatus(OrderUtil.STATUS_REFUND_CONFIRM);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 商品货品数量增加
        List<NearbyshopOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
        for (NearbyshopOrderGoods orderGoods : orderGoodsList) {
            Integer productId = orderGoods.getProductId();
            Short number = orderGoods.getNumber();
            if (productService.addStock(productId, number) == 0) {
                throw new RuntimeException("商品货品库存增加失败");
            }
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 退款成功通知用户, 例如“您申请的订单退款 [ 单号:{1} ] 已成功，请耐心等待到账。”
        // 注意订单号只发后6位
        notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND, new String[]{order.getOrderSn().substring(8, 14)});

        return ResponseUtil.ok();
    }

    /**
     * 订单申请退款
     * <p>
     * 1. 检测当前订单是否能够退款；
     * 2. 设置订单申请退款状态。
     *
     * @return 订单退款操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Object refundGroupNative(Integer orderId) {
        NearbyshopOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isRefund()) {
            return ResponseUtil.fail("订单不能退款");
        }

        NearbyshopOrder2 order2 = orderService2.getById(orderId);
        NearbyshopOrderRefund refund = new NearbyshopOrderRefund();
        BeanUtils.copyProperties(order2,refund);
        refund.setOrderId(order2.getId());
        refund.setId(null);
        refund.setApplyTime(new Date());
        refund.setHandleTime(new Date());
        refund.setRefundStatus(1);
        refund.setRefundPrice(order2.getActualPrice());
        refund.setRefundReason("团购失败退款");
        refund.setRefundBy("3");
        //多加入一个状态：已采购
        if(order.getOrderStatus().equals(OrderUtil.STATUS_PAY) && order.getPurchaseStatus().equals(1)){
            refund.setOrderStatus(OrderUtil.STATUS_PURCHASE.intValue());
        }
        //设置商品数量
        int gnum = 0;
        int i = 1;
        List<NearbyshopOrderGoods> goodsList = orderGoodsService.queryByOid(order.getId());
        for(NearbyshopOrderGoods og : goodsList){
            gnum += og.getNumber();
        }
        refund.setGoodsNum(gnum);
        refundService.save(refund);

        // 设置订单申请退款状态
        order.setOrderStatus(OrderUtil.STATUS_REFUND);
//        if (orderService.updateWithOptimisticLocker(order) == 0) {
//            return ResponseUtil.updatedDateExpired();
//        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 有用户申请退款，邮件通知运营人员
        //notifyService.notifyMail("订单退款", order.toString());


        //新增方法，申请退款后直接退
        /*Map<String, String> context = new HashMap<>();
        context.put("tranId", order.getOrderSn());
        context.put("amount", order.getActualPrice().toPlainString());

        try {
            Map<String, String> result = cnlPayService.refundApply(context);
            if (!result.get(CMM_PARAM_RETURN_CODE).equals(SUC_RETURN_CODE)) {
                logger.warn("refund fail: " + result.get(CMM_PARAM_RETURN_MSG));
                return ResponseUtil.fail(WxResponseCode.ORDER_REFUND_FAILED, "订单退款失败");
            }
            order.setShipSn(result.get(UP_CORG_TRAN_ID));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
*/

        // 微信原生退款
        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
        wxPayRefundRequest.setOutTradeNo(order.getOrderSn());
        wxPayRefundRequest.setOutRefundNo("refund_" + order.getOrderSn());
        // 元转成分
        Integer totalFee = order.getActualPrice().multiply(new BigDecimal(100)).intValue();
        wxPayRefundRequest.setTotalFee(totalFee);
        wxPayRefundRequest.setRefundFee(totalFee);

        WxPayRefundResult wxPayRefundResult = null;
        try {
            wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
        } catch (WxPayException e) {
            e.printStackTrace();
            return ResponseUtil.fail( "订单退款失败");
        }
        if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
            logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
            return ResponseUtil.fail( "订单退款失败");
        }
        if (!wxPayRefundResult.getResultCode().equals("SUCCESS")) {
            logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
            return ResponseUtil.fail( "订单退款失败");
        }


        // 设置订单取消状态
        order.setOrderStatus(OrderUtil.STATUS_REFUND_CONFIRM);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 商品货品数量增加
        List<NearbyshopOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
        for (NearbyshopOrderGoods orderGoods : orderGoodsList) {
            Integer productId = orderGoods.getProductId();
            Short number = orderGoods.getNumber();
            if (productService.addStock(productId, number) == 0) {
                throw new RuntimeException("商品货品库存增加失败");
            }
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 退款成功通知用户, 例如“您申请的订单退款 [ 单号:{1} ] 已成功，请耐心等待到账。”
        // 注意订单号只发后6位
        notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND, new String[]{order.getOrderSn().substring(8, 14)});

        return ResponseUtil.ok();
    }

    @Transactional
    public Object refundApply(NearbyshopOrderRefund refund) {
        NearbyshopOrder2 order = orderService2.getById(refund.getOrderId());
        BeanUtils.copyProperties(order,refund);
        refund.setOrderId(order.getId());
        refund.setId(null);
        refund.setApplyTime(new Date());
        refund.setHandleTime(new Date());
        refund.setRefundPrice(refund.getRefundPrice());
        refund.setRefundStatus(1);
        if(StringUtils.isEmpty(refund.getRefundReason())){
            refund.setRefundReason("后台记录退款");
        }
        refund.setRefundBy("2");

        //设置退款商品数量
        int gnum = 0;
        int i = 1;
        List<NearbyshopOrderGoods> goodsList = orderGoodsService.queryByOid(order.getId());
        for(NearbyshopOrderGoods og : goodsList){
            gnum += og.getNumber();
        }
        refund.setGoodsNum(gnum);
        refundService.save(refund);

        NearbyshopOrder2 orderUpdate = new NearbyshopOrder2();
        orderUpdate.setId(order.getId());
        orderUpdate.setOrderStatus(OrderUtil.STATUS_REFUND.intValue());
        orderService2.updateById(orderUpdate);

        return refund("{\"orderId\":"+order.getId()+",\"refundMoney\":"+refund.getRefundPrice()+"}");
    }

    @Transactional(rollbackFor = Exception.class)
    public Object refundApplyNative(NearbyshopOrderRefund refund) {
        NearbyshopOrder2 order = orderService2.getById(refund.getOrderId());
        BeanUtils.copyProperties(order,refund);
        refund.setOrderId(order.getId());
        refund.setId(null);
        refund.setApplyTime(new Date());
        refund.setHandleTime(new Date());
        refund.setRefundPrice(order.getActualPrice());
        refund.setRefundStatus(1);
        if(StringUtils.isEmpty(refund.getRefundReason())){
            refund.setRefundReason("后台记录退款");
        }
        refund.setRefundBy("2");

        //设置退款商品数量
        int gnum = 0;
        int i = 1;
        List<NearbyshopOrderGoods> goodsList = orderGoodsService.queryByOid(order.getId());
        for(NearbyshopOrderGoods og : goodsList){
            gnum += og.getNumber();
        }
        refund.setGoodsNum(gnum);
        refundService.save(refund);

        NearbyshopOrder orderUpdate = new NearbyshopOrder();
        orderUpdate.setId(order.getId());
        orderUpdate.setOrderStatus(OrderUtil.STATUS_REFUND);
        orderService.updateWithOptimisticLocker(orderUpdate);

        return refundNative("{\"orderId\":"+order.getId()+",\"refundMoney\":"+order.getActualPrice()+"}");
    }
}
